不同於上一篇的 Sanity 圖片 url
直接在查詢圖片時就把圖片 url 查詢出來或是用 _ref
組合出圖片的 url。
這次要使用的是 @Sanity/image-url 這套官方的圖片套件。
要使用 @Sanity/image-url
不難,首先 npm 引入套件:
npm install @sanity/image-url --save
並且 import 套件再傳入 Saniry 連線的 client 物件:
import { createClient } from "next-sanity";
import { dataset, projectId } from "../env";
// 引入套件
import imageUrlBuilder from "@sanity/image-url";
import type { SanityImageSource } from "@sanity/image-url/lib/types/types";
// Sanity 連線 client 物件
export const client = createClient({
projectId,
dataset,
useCdn: true,
});
export function urlFor(source: SanityImageSource) {
// 傳入 client 物件作為連線資訊後
return imageUrlBuilder(client)
.image(source); // <- 再傳入 Sanity 的圖片資源物件
}
接下來要使用 Sanity 圖片的地方只要使用 export
出來的 urlFor
就可以了。
import { client, urlFor } from "@/app/sanity/lib/client";
export default async function ImageTest() {
// 取得文章物件
const post = await client.fetch(BLOG_POSTS_BY_SLUG_QUERY_TEST, {
slug: "圖解-java-zip-包裹檔案",
});
// ...
// 圖片 url
console.log(urlFor(post.heroImage).url());
return (
// ...
);
}
只要將圖片物件傳進去 urlFor
,並呼叫 url()
方法就可以了。
@Sanity/image-url 不只可以作為呼叫圖片 url 的方法,它還提供了圖片寬高、blur、rect、quality 等等的屬性設定方法。
// {imageUrl}.jpg
urlFor(post.heroImage).url()
// {imageUrl}.jpg?w=200
urlFor(post.heroImage).width(200).url()
// {imageUrl}.jpg?rect=100,50,215,200
urlFor(post.heroImage).rect(100, 50, 215, 200).url()
// {imageUrl}.jpg?q=100
urlFor(post.heroImage).quality(100).url()
// {imageUrl}.jpg?h=300&q=20
urlFor(post.heroImage).height(300).quality(20).url()
在 next/image
Component 中,有一個 prop 是 loader,他接受一個 callback 方法並且回 width
, src
, quality
屬性。
分別傳入一些圖片 Image 載入時的的狀態值,對於載入時渲染圖片是很有幫助的。
這邊單獨為 Sanity 建立一個圖片顯示的 Component,叫做 SanityImage.tsx
:
// app/components/SanityImage.tsx
"use client";
import { urlFor } from "@/app/sanity/lib/client";
import Image, { type ImageProps } from "next/image";
import type { SanityImageSource } from "@sanity/image-url/lib/types/types";
// 將 next/image 中的 ImageProps 提取出來,並將 src 屬性移除
// 並且加入 source 屬性,這樣就可以將 Sanity 的圖片資料傳入
type Props = Omit<ImageProps, "src"> & {
source: SanityImageSource;
};
export default function SanityImage({ source, alt, ...props }: Props) {
return (
<Image
{...props}
src="image src doesn't matter in this case"
alt={alt}
loader={({ width, quality = 100 }) =>
// 根據傳入的 source 取得圖片的 URL
// 並且指定寬度和品質,達到最佳的圖片效果
urlFor(source).width(width).quality(quality).url()
}
/>
);
}
接下來可以引入到我們原本的 app/[slug]/page.tsx
Component 中了:
// ...
import SanityImage from "@/app/components/SanityImage";
export default async function Post({ params }: { params: { slug: string } }) {
// ...
return (
<div className="post">
{/* ... */}
<div className="relative w-full max-w-[770px] aspect-[770/480]">
<SanityImage
source={post.heroImage}
alt={`${post.title} banner image`}
fill
sizes="(max-width: 770px) 50vw, 770px"
/>
</div>
{/* ... */}
</div>
);
}
這樣就會有個可顯示 Sanity 圖片並且具備基礎 RWD 效果的 Component 了!